package com.gitee.target123.develop.login.util;

import com.gitee.target123.develop.login.properties.ExtendProperties;
import com.gitee.target123.develop.login.properties.JustAuthProperties;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.request.*;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class AuthRequestFactory {

    private JustAuthProperties properties;
    private AuthStateCache authStateCache;

    public AuthRequestFactory(JustAuthProperties properties, AuthStateCache authStateCache) {
        this.properties = properties;
        this.authStateCache = authStateCache;
    }

    /**
     * 返回当前Oauth列表
     * @return Oauth列表
     */
    public List<String> oauthList() {
        // 默认列表
        List<String> defaultList = this.properties.getType().keySet().stream().map(Enum::name).collect(Collectors.toList());
        // 扩展列表
        ExtendProperties extend = this.properties.getExtend();
        if (null != extend) {
            try {
                Class enumClass = extend.getEnumClass();
                List<String> names = EnumUtil.getNames(enumClass);
                // 扩展列表
                List<String> extendList = extend.getConfig().keySet().stream()
                        .filter(x -> names.contains(x.toUpperCase()))
                        .map(String::toUpperCase)
                        .collect(Collectors.toList());

                defaultList.addAll(extendList);
            }catch (Exception e){

            }
        }
        return defaultList;
    }

    /**
     * 返回AuthRequest对象
     * @param source {@link AuthSource}
     * @return {@link AuthRequest}
     */
    public AuthRequest get(String source) {
        source = source.trim();
        if (StringUtils.isEmpty(source)) {
            throw new AuthException(AuthResponseStatus.NO_AUTH_SOURCE);
        }

        // 获取 JustAuth 中已存在的
        AuthRequest authRequest = getDefaultRequest(source);

        // 如果获取不到则尝试取自定义的
        if (authRequest == null) {
            authRequest = getExtendRequest(this.properties.getExtend().getEnumClass(), source);
        }

        if (authRequest == null) {
            throw new AuthException(AuthResponseStatus.UNSUPPORTED);
        }

        return authRequest;
    }

    /**
     * 获取自定义的 request
     * @param clazz  枚举类 {@link AuthSource}
     * @param source {@link AuthSource}
     * @return {@link AuthRequest}
     */
    private AuthRequest getExtendRequest(Class clazz, String source) {
        String upperCase = source.toUpperCase();
        try {
            EnumUtil.fromString(clazz, upperCase);
        } catch (IllegalArgumentException e) {
            // 无自定义匹配
            return null;
        }

        ExtendProperties.ExtendRequestConfig extendRequestConfig = null;
        Map<String, ExtendProperties.ExtendRequestConfig> extendConfig = this.properties.getExtend().getConfig();
        for (Map.Entry<String, ExtendProperties.ExtendRequestConfig> entry : extendConfig.entrySet()) {
            if (entry.getKey().toUpperCase().equals(upperCase)){
                extendRequestConfig = entry.getValue();
                break;
            }
        }

        if (extendRequestConfig != null) {
            Class<? extends AuthRequest> requestClass = extendRequestConfig.getRequestClass();

            if (requestClass != null) {
                // 反射获取 Request 对象，所以必须实现 2 个参数的构造方法
                return (AuthRequest)ReflectUtils.newInstance(requestClass,
                        new Class[]{AuthConfig.class,AuthStateCache.class},
                        new Object[]{extendRequestConfig,this.authStateCache});
//                return ReflectUtil.newInstance(requestClass, (AuthConfig) extendRequestConfig, this.authStateCache);
            }
        }

        return null;
    }

    /**
     * 获取默认的 Request
     * @param source {@link AuthSource}
     * @return {@link AuthRequest}
     */
    private AuthRequest getDefaultRequest(String source) {
        AuthDefaultSource authDefaultSource;

        try {
            authDefaultSource = EnumUtil.fromString(AuthDefaultSource.class, source.toUpperCase());
        } catch (IllegalArgumentException e) {
            // 无自定义匹配
            return null;
        }

        AuthConfig config = this.properties.getType().get(authDefaultSource);
        // 找不到对应关系，直接返回空
        if (config == null) {
            return null;
        }

        switch (authDefaultSource) {
            case WECHAT_MP:
                return new AuthWeChatMpRequest(config, this.authStateCache);
            case QQ:
                return new AuthQqRequest(config, this.authStateCache);
            case DOUYIN:
                return new AuthDouyinRequest(config, this.authStateCache);
            case TAOBAO:
                return new AuthTaobaoRequest(config, this.authStateCache);
            case ALIPAY:
                return new AuthAlipayRequest(config, this.authStateCache);
            case WEIBO:
                return new AuthWeiboRequest(config, this.authStateCache);
            case BAIDU:
                return new AuthBaiduRequest(config, this.authStateCache);
            case GITHUB:
                return new AuthGithubRequest(config, this.authStateCache);
            case GITEE:
                return new AuthGiteeRequest(config, this.authStateCache);
            case DINGTALK:
                return new AuthDingTalkRequest(config, this.authStateCache);
            case CODING:
                return new AuthCodingRequest(config, this.authStateCache);
            case TENCENT_CLOUD:
                return new AuthTencentCloudRequest(config, this.authStateCache);
            case OSCHINA:
                return new AuthOschinaRequest(config, this.authStateCache);
            case GOOGLE:
                return new AuthGoogleRequest(config, this.authStateCache);
            case FACEBOOK:
                return new AuthFacebookRequest(config, this.authStateCache);
            case LINKEDIN:
                return new AuthLinkedinRequest(config, this.authStateCache);
            case MICROSOFT:
                return new AuthMicrosoftRequest(config, this.authStateCache);
            case MI:
                return new AuthMiRequest(config, this.authStateCache);
            case TOUTIAO:
                return new AuthToutiaoRequest(config, this.authStateCache);
            case TEAMBITION:
                return new AuthTeambitionRequest(config, this.authStateCache);
            case RENREN:
                return new AuthRenrenRequest(config, this.authStateCache);
            case PINTEREST:
                return new AuthPinterestRequest(config, this.authStateCache);
            case STACK_OVERFLOW:
                return new AuthStackOverflowRequest(config, this.authStateCache);
            case HUAWEI:
                return new AuthHuaweiRequest(config, this.authStateCache);
            case WECHAT_ENTERPRISE:
                return new AuthWeChatEnterpriseRequest(config, this.authStateCache);
            case GITLAB:
                return new AuthGitlabRequest(config, this.authStateCache);
            case KUJIALE:
                return new AuthKujialeRequest(config, this.authStateCache);
            case ELEME:
                return new AuthElemeRequest(config, this.authStateCache);
            case MEITUAN:
                return new AuthMeituanRequest(config, this.authStateCache);
            case TWITTER:
                return new AuthTwitterRequest(config, this.authStateCache);
            default:
                return null;
        }
    }
}
